/*
* This file is a part of the open-eBackup project.
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
* If a copy of the MPL was not distributed with this file, You can obtain one at
* http://mozilla.org/MPL/2.0/.
*
* Copyright (c) [2024] Huawei Technologies Co.,Ltd.
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*/
#ifndef HOST_ARCHIVE_RESTORE_H
#define HOST_ARCHIVE_RESTORE_H

#include "Module/src/common/JsonHelper.h"
#include "Backup.h"
#include "Scanner.h"

#include "BasicJob.h"
#include "common/HetroCommonService.h"
#include "ArchiveClient.h"
#include "ArchiveDownloadFile.h"
#include "common/CleanMemPwd.h"

struct NasAuthExtent {
    std::string krb5Conf {};
    std::string secret {};
    std::string keytab {};
    std::string configModel {};

    BEGIN_SERIAL_MEMEBER
    SERIAL_MEMBER_TO_SPECIFIED_NAME(krb5Conf, krb5Conf)
    SERIAL_MEMBER_TO_SPECIFIED_NAME(secret, secret)
    SERIAL_MEMBER_TO_SPECIFIED_NAME(keytab, keytab)
    SERIAL_MEMBER_TO_SPECIFIED_NAME(configModel, configModel)
    END_SERIAL_MEMEBER
};

struct SourceNasShare {
    std::string id;
    std::string sharePath;
    std::string ip;
    std::string domainName;
    std::string protocol;
    std::string protocolVersion;
    std::string user;                // cifs
    std::string password;            // cifs
    std::string encryption;          // cifs
    uint32_t blockSize {0};          // cifs
    Authentication auth {};
    NasAuthExtent nasShareAuthExt {};

    ~SourceNasShare()
    {
        Module::CleanMemoryPwd(password);
    }
};

struct ArchiveRestoreStrategyShare {
    std::string fileReplaceStrategy;
    std::string targetLocation;
    std::string targetPath;
    std::string sharePath;
    BEGIN_SERIAL_MEMEBER
    SERIAL_MEMBER_TO_SPECIFIED_NAME(fileReplaceStrategy, fileReplaceStrategy)
    SERIAL_MEMBER_TO_SPECIFIED_NAME(targetLocation, targetLocation)
    SERIAL_MEMBER_TO_SPECIFIED_NAME(targetPath, targetPath)
    SERIAL_MEMBER_TO_SPECIFIED_NAME(sharePath, sharePath)
    END_SERIAL_MEMEBER
};

struct FileSystemSourceInfo {
    std::string authType;
    std::string authKey;
    std::string authPwd;
    std::string protocol;
    std::string shareIp;
    std::string sharePath;
    std::string fileReplaceStrategy;
    std::string targetLocation;
    std::string targetPath;
    BEGIN_SERIAL_MEMEBER
    SERIAL_MEMBER_TO_SPECIFIED_NAME(authType, authType)
    SERIAL_MEMBER_TO_SPECIFIED_NAME(authKey, authKey)
    SERIAL_MEMBER_TO_SPECIFIED_NAME(authPwd, authPwd)
    SERIAL_MEMBER_TO_SPECIFIED_NAME(protocol, protocol)
    SERIAL_MEMBER_TO_SPECIFIED_NAME(shareIp, shareIp)
    SERIAL_MEMBER_TO_SPECIFIED_NAME(sharePath, sharePath)
    SERIAL_MEMBER_TO_SPECIFIED_NAME(fileReplaceStrategy, fileReplaceStrategy)
    SERIAL_MEMBER_TO_SPECIFIED_NAME(targetLocation, targetLocation)
    SERIAL_MEMBER_TO_SPECIFIED_NAME(targetPath, targetPath)
    END_SERIAL_MEMEBER
};

struct ShareSourceInfo {
    std::string authType;
    std::string domainName;
    std::string shareIp;
    std::string shareMode;
    std::string encryption;
    BEGIN_SERIAL_MEMEBER
    SERIAL_MEMBER_TO_SPECIFIED_NAME(authType, authMode)
    SERIAL_MEMBER_TO_SPECIFIED_NAME(domainName, domainName)
    SERIAL_MEMBER_TO_SPECIFIED_NAME(shareIp, ip)
    SERIAL_MEMBER_TO_SPECIFIED_NAME(shareMode, shareMode)
    SERIAL_MEMBER_TO_SPECIFIED_NAME(encryption, encryption)
    END_SERIAL_MEMEBER
};

struct BackupStatistic {
    uint64_t noOfDirToBackup    = 0;        /* No of directories to be backed up */
    uint64_t noOfFilesToBackup  = 0;        /* No of files to be backed up */
    uint64_t noOfBytesToBackup  = 0;        /* No of bytes (in KB) to be backed up */
    uint64_t noOfDirToDelete    = 0;        /* No of directories to be deleted */
    uint64_t noOfFilesToDelete  = 0;        /* No of files to be deleted */
    uint64_t noOfDirCopied      = 0;        /* No of directories copied */
    uint64_t noOfFilesCopied    = 0;        /* No of files copied */
    uint64_t noOfBytesCopied    = 0;        /* No of bytes (in KB) copied */
    uint64_t noOfDirDeleted     = 0;        /* No of directories deleted */
    uint64_t noOfFilesDeleted   = 0;        /* No of files deleted */
    uint64_t noOfDirFailed      = 0;        /* No of directories failed to be copied/deleted */
    uint64_t noOfFilesFailed    = 0;        /* No of files failed to be copied/deleted */
    uint64_t backupspeed        = 0;        /* Backup speed (in KBps) */
    time_t   startTime          = 0;        /* Start time of backup phase */
    uint64_t noOfSrcRetryCount  = 0;        /* No of src side retry count */
    uint64_t noOfDstRetryCount  = 0;        /* No of dst side retry count */
    time_t   lastLogReportTime  = 0;        /* Last time (epoch seconds) when we report log to PM */

    BEGIN_SERIAL_MEMEBER
    SERIAL_MEMBER_TO_SPECIFIED_NAME(noOfDirToBackup, noOfDirToBackup)
    SERIAL_MEMBER_TO_SPECIFIED_NAME(noOfFilesToBackup, noOfFilesToBackup)
    SERIAL_MEMBER_TO_SPECIFIED_NAME(noOfBytesToBackup, noOfBytesToBackup)
    SERIAL_MEMBER_TO_SPECIFIED_NAME(noOfDirToDelete, noOfDirToDelete)
    SERIAL_MEMBER_TO_SPECIFIED_NAME(noOfFilesToDelete, noOfFilesToDelete)
    SERIAL_MEMBER_TO_SPECIFIED_NAME(noOfDirCopied, noOfDirCopied)
    SERIAL_MEMBER_TO_SPECIFIED_NAME(noOfFilesCopied, noOfFilesCopied)
    SERIAL_MEMBER_TO_SPECIFIED_NAME(noOfBytesCopied, noOfBytesCopied)
    SERIAL_MEMBER_TO_SPECIFIED_NAME(noOfDirDeleted, noOfDirDeleted)
    SERIAL_MEMBER_TO_SPECIFIED_NAME(noOfFilesDeleted, noOfFilesDeleted)
    SERIAL_MEMBER_TO_SPECIFIED_NAME(noOfDirFailed, noOfDirFailed)
    SERIAL_MEMBER_TO_SPECIFIED_NAME(noOfFilesFailed, noOfFilesFailed)
    SERIAL_MEMBER_TO_SPECIFIED_NAME(backupspeed, backupspeed)
    SERIAL_MEMBER_TO_SPECIFIED_NAME(startTime, startTime)
    SERIAL_MEMBER_TO_SPECIFIED_NAME(noOfSrcRetryCount, noOfSrcRetryCount)
    SERIAL_MEMBER_TO_SPECIFIED_NAME(noOfDstRetryCount, noOfDstRetryCount)
    SERIAL_MEMBER_TO_SPECIFIED_NAME(lastLogReportTime, lastLogReportTime)
    END_SERIAL_MEMEBER
};

enum class ArchiveJobState {
    NONE = -1,
    SUCCESS = 0,
    FAILED = 1,
    RUNNING = 2,
    ABORT = 3,
    NASSHARE_ERROR = 4,
    EMPTY_COPY = 5,
    PARTIAL_SUCCESS = 6,
    SKIP_PHASE = 7
};

class NasArchiveRestore : public HetroCommonService {
public:
    NasArchiveRestore() {}
    virtual ~NasArchiveRestore();
    EXTER_ATTACK int PrerequisiteJob() override;
    EXTER_ATTACK int GenerateSubJob() override;
    EXTER_ATTACK int ExecuteSubJob() override;
    EXTER_ATTACK int PostJob() override;

private:
    int PrerequisiteJobInner();
    int GenerateSubJobInner();
    int ExecuteSubJobInner();
    int PostJobInner();
    inline bool IsAbort() const;
    bool SendJobReportForAliveness();
    bool GetRestoreJobInfo();
    int ExecuteCheckSubJobInner();
    // init
    bool InitJobInfo();
    bool InitRepoInfo();
    bool InitRestoreInfo();
    bool InitArchiveInfo();
    bool InitInfo();
    void PrintInfo() const;
    inline bool IsFineRestore() const;
    bool InitCacheRepoDir();
    bool GenerateSubJobList(std::vector<SubJob> &subJobList, std::vector<std::string> &ctrlFileList,
        const std::string &dstCtrlFileRelPath, const std::string &ctrlFileFullPath);
    bool InitArchiveClient();
    bool InitProtocolInfo();
    inline bool IsRestoreByCIFS() const;
    inline bool IsRestoreByNFS() const;
    inline bool IsUseKerberos() const;
    inline bool IsFileSystemCopy() const;
    inline bool IsNasShareCopy() const;

    bool InitRestoreInfoFileSystem();
    bool InitRestoreInfoNasShare();
    bool FillIplistForNativeRestore();
    bool InitKerberos();
    void IdentifyFileReplaceStrategy(const std::string& strategy);
    bool CheckAvailableShareInfo();
    bool CheckConnectNFS(const std::string& protoVersion);
    bool CheckConnectSMB(const std::string& ip, Module::SmbVersion version);
    void PrintJobInfo() const;
    std::string RemoveShareName(const std::string& path);
    void SetArchiveSourceInfo();

    // resource stats
    bool InitMainResources();
    bool InitSubBackupJobResources();
    bool QueryMainScanResources();
    bool DeleteSharedResources();
    bool UpdateSubBackupStats();
    void UpdateMainStatsIfReport();  // 当需要上报的时候更新mainStats和上报时间
    bool GetBackupCopyInfo(const std::string& backupCopyInfo);
    // gen
    bool DownloadMetaFile();
    bool StartScanner();
    inline bool IsDir(const std::string& name) const;
    void AddFilterRule(ScanConfig& scanConfig);
    void FillScanConfig(ScanConfig& scanConfig);
    void MonitorScan();
    bool ReportScannerRunningStatus();
    bool CreateSubTasksFromCtrlFile(SubJobStatus::type &jobStatus, uint32_t subTaskType, bool isFinal = false);
    void ReportGenerateSubJob();
    void SetArchiveJobState();
    bool GetSubJobInfoByFileName(int copyOrder, const std::string &fileName, std::string &subTaskName,
        int &subTaskType, int &subTaskPrio);
    bool PrepareMetaFile();
    bool UncompressMetafile() const;
    bool UnzipNewMetaGZipFiles() const;
    bool UnzipOldMetafileZip(const std::string& oldMetafileZipPath) const;
    bool CopyMetaFile() const;
    void ReportCopyPhaseStart();

    void UpdateScannerStatistics(HetroNativeScanStatistics &scanStatistics, std::string &jobId);
    void PrintScannerStatistics(HetroNativeScanStatistics &scanStatistics);
    bool CheckFilePathAndGetSrcFileList(std::string srcDir, std::string dstDir,
            std::vector<std::string> &srcFileList);
    bool GetAvailableIpSMB();
    std::string CutPrefixSlash(const std::string& path) const;
    // excute
    bool StartRestore();
    BackupParams FillRestoreConfig(const HetroBackupSubJob& subJobInfo);
    void FillSrcParams(BackupParams& backupParams, const HetroBackupSubJob& subJobInfo);
    void FillDstParams(BackupParams& backupParams);
    void FillParamsNFS(BackupParams& backupParams);
    void FillParamsCIFS(BackupParams& backupParams);

    SubJobStatus::type MonitorRestore();
    bool IsBackupStatusInprogress(SubJobStatus::type &jobStatus);
    bool CalcuMainBackupStats(HetroNativeBackupStats& mainBackupStats);
    void PrintBackupStatistics(const HetroNativeBackupStats &backupStatistic);
    bool ReportBackupRunningStatus(const HetroNativeBackupStats& mainBackupStats);
    void BackupStatisticClassConvertToStruct(
        const BackupStats& backupStats, HetroNativeBackupStats& backupStatistic, uint32_t backupPhrase);
    bool IsSkipHardlinkPhase(uint32_t subTaskType);

    // post
    void ReportPostJob();
    void CleanCache();

    // common
    bool CheckConnect();
    void ReportTapeNotSupportDirectRestore();

private:
    // common info
    std::string m_jobCtrlPhase; // 4 job phase
    std::shared_ptr<AppProtect::RestoreJob> m_jobInfoPtr {nullptr};
    // job info
    std::string m_jobId;
    std::string m_subJobId;
    std::string m_copyId;
    bool m_isAggCopy {false};
    AggCopyExtendInfo m_aggCopyInfo;
    int64_t m_lastJobReportTime {0};
    SourceNasShare m_nasShare {};                    // 恢复目标端nasshare
    FileSystemSourceInfo  m_fileSystemSourceInfo {}; // 恢复目标端文件系统类型的信息
    ShareSourceInfo m_shareSourceInfo {};            // 恢复目标端nas共享类型的信息
    ArchiveRestoreStrategyShare m_strategyShare {};  // 共享模式策略
    std::string m_restoreLocationType;               // 恢复的位置类型 原位置、新位置、本机位置
    std::string m_protectSubtype;                    // 保护设备类型 NasShare/NasFileSystem
    // restore info
    std::string m_statsPath;
    std::vector<std::string> m_restorePathList;
    std::vector<std::string> m_fineRestoreObj;
    std::string m_cacheMdPath;
    std::string m_scanInputMetePath;
    std::string m_downloadMetePath;
    std::string m_scanControlFilePath;
    std::string m_backupControlFilePath;
    std::string m_sourceContextMd; // source_policy_3e789c80dba046c7bce7d4fa14e29d61_Context_Global_MD
    std::string m_sourceContext; // source_policy_3e789c80dba046c7bce7d4fa14e29d61_Context
    std::string m_dataPath; // 源端归档副本的路径
    RestoreReplacePolicy m_coveragePolicy {RestoreReplacePolicy::NONE};
    std::string m_fineRestorePath; // 目标端路径
    // repo info
    std::string m_cacheFs;
    std::string m_cacheFsPath;
    std::string m_parentDir;
    // archive info
    ArchiveServerInfo m_archiveServerInfo;
    std::string m_archiveFsId;
    bool m_isTapeRestore { false };
    // restore job context
    std::string m_jobStartTime;
    ArchiveJobState m_jobState {ArchiveJobState::NONE};
    BackupPhaseStatus m_backupStatus;
    // gen
    HetroNativeScanStatistics m_scanStats {};
    int64_t m_lastScannerReportTime {0};
    std::atomic<bool> m_isPrepareMetaFinish {false};
    std::string m_fileSystemMetaPath;
    // excute
    HetroNativeBackupStats m_backupStats {};
    HetroNativeBackupStats m_subBackupStats {};
    // other object
    std::shared_ptr<ArchiveClient> m_archiveClient {nullptr}; // TO-DO 后续使用对象池存放多个归档客户端

    std::unique_ptr<FS_Backup::Backup> m_backup {nullptr};
};
#endif // HOST_ARCHIVE_RESTORE_H